/////////////////////////////////////////////////////////////////////////////
//
//
//Created:               190915 Xue Zhaojie
//1st version Finished:
//Modified:
//
//
//////////////////////////////////////////////////////////////////////////////

package app;

import datastructure.Instance;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.StringTokenizer;

public class Generator_U {

    int divide = 0;
    int numofCustomer = 0;
    int numofPFC = 0;
    int numofTask = 0;

    double a = 0; // platoon saving factor
    double b = 0;// platoon saving factor
    double Len = 0; // maximum platoon length

    double c1 = 0; // cost driver
    double c2 = 0; //cost fuel
    double miu = 0;

    double delta[];
    double Fi = 0;
    double Fm = 0;


    double[][] distanceMatrix;
    int[][] ODdemand;

    double[][] coordinateofPFC;
    double[][] coordinateofCustomer;
    double[][] coordinate;

    public static double myRound(double v, int scale) {
        String temp = "#0.";
        for (int i = 0; i < scale; i++) {
            temp += "0";
        }
        return Double.valueOf(new java.text.DecimalFormat(temp).format(v)).doubleValue();
    }

    public Instance generate(int divide, int experimentnumber, String time) {
        Instance instance = new Instance();

        this.divide = divide;
        this.numofCustomer = divide * divide;
        this.numofPFC = (divide + 1) * (divide + 1);
        this.numofTask = numofCustomer + numofPFC;

        c1 = 60;
        c2 = 6;
        miu = 20;
        a = 0.05;
        b = 0.1;
        Len = 3;


        Fi = 750;
        Fm = 1500;

        delta = new double[numofPFC];
        for (int i = 0; i < numofPFC; i++) {
            delta[i] = 50 + (int) (Math.random() * 30);
        }

        distanceMatrix = new double[numofTask][numofTask];
        ODdemand = new int[numofCustomer][numofCustomer];

        coordinateofCustomer = new double[numofCustomer][2];
        coordinateofPFC = new double[numofPFC][2];
        coordinate = new double[numofTask][2];

        double areaParameter = 500;

        int index = 0;
        for (int i = 0; i < divide; i++) {
            for (int j = 0; j < divide; j++) {
                coordinateofCustomer[index][0] = (areaParameter / divide) / 2 + j * (areaParameter / divide);
                coordinateofCustomer[index][1] = (areaParameter / divide) / 2 + i * (areaParameter / divide);
                coordinate[index][0] = coordinateofCustomer[index][0];
                coordinate[index][1] = coordinateofCustomer[index][1];
                index++;
            }
        }

        index = 0;
        for (int i = 0; i < divide + 1; i++) {
            for (int j = 0; j < divide + 1; j++) {
                coordinateofPFC[index][0] = j * (areaParameter / divide);
                coordinateofPFC[index][1] = i * (areaParameter / divide);
                coordinate[index + numofCustomer][0] = coordinateofPFC[index][0];
                coordinate[index + numofCustomer][1] = coordinateofPFC[index][1];
                index++;
            }
        }

        for (int i = 0; i < numofCustomer; i++) {
            for (int j = 0; j < numofCustomer; j++) {
                if (i != j) {
                    double a = 1.0 / (double) divide;
                    if (Math.random() < a) {
                        ODdemand[i][j] = 10 + (int) (Math.random() * 90);
                    } else {
                        ODdemand[i][j] = 0;
                    }
                }
            }
        }

        for (int i = 0; i < numofTask; i++) {
            for (int j = 0; j < numofTask; j++) {
                distanceMatrix[i][j] = distance(coordinate[i][0], coordinate[i][1],
                        coordinate[j][0], coordinate[j][1]);
            }
        }

        for (int i = 0; i < distanceMatrix.length; i++) {
            for (int j = 0; j < distanceMatrix[0].length; j++) {
                distanceMatrix[i][j] = myRound(distanceMatrix[i][j] / 60, 2);
            }
        }

        instance.divide = divide;
        instance.numofCustomer = numofCustomer;
        instance.numofPFC = numofPFC;
        instance.numofTask = numofTask;

        instance.a = a;
        instance.b = b; // platoon saving factor
        instance.Len = Len; // maximum platoon length

        instance.c1 = c1; // cost weight
        instance.c2 = c2;
        instance.miu = miu;
        instance.Fi = Fi;
        instance.Fm = Fm;
        instance.delta = delta;


        instance.ODdemand = ODdemand;
        instance.distanceMatrix = distanceMatrix;

        instance.coordinateofPFC = coordinateofPFC;
        instance.coordinateofCustomer = coordinateofCustomer;

        return instance;
    }

    public void fileOutput(int divide, int experimentnumber, String time) throws IOException {
        String outputFilePath = "data/random_U/" + divide + ".txt";
        FileWriter fw = new FileWriter(outputFilePath);
        fw.write("divide\r\n" + divide + "\r\n");
        fw.write("customers\r\n" + numofCustomer + "\r\n");
        fw.write("PFC\r\n" + numofPFC + "\r\n");
        fw.write("Task\r\n" + numofTask + "\r\n");
        fw.write("c1\r\n" + c1 + "\r\n");
        fw.write("c2\r\n" + c2 + "\r\n");
        fw.write("miu\r\n" + miu + "\r\n");
        fw.write("a\r\n" + a + "\r\n");
        fw.write("b\r\n" + b + "\r\n");
        fw.write("Len\r\n" + Len + "\r\n");
        fw.write("Fi\r\n" + Fi + "\r\n");
        fw.write("Fm\r\n" + Fm + "\r\n");

        fw.write("delta\r\n");
        for (int i = 0; i < numofPFC; i++) {
            fw.write(delta[i] + "\r\n");
        }

        fw.write("ODdemand\r\n");
        for (int i = 0; i < numofCustomer; i++) {
            for (int j = 0; j < numofCustomer; j++) {
                fw.write(ODdemand[i][j] + "\r\n");
            }
        }

        fw.write("customer coordinate\r\n");
        for (int i = 0; i < coordinateofCustomer.length; i++) {
            for (int j = 0; j < coordinateofCustomer[0].length; j++) {
                fw.write(coordinateofCustomer[i][j] + "\r\n");
            }
        }

        fw.write("PFC coordinate\r\n");
        for (int i = 0; i < coordinateofPFC.length; i++) {
            for (int j = 0; j < coordinateofPFC[0].length; j++) {
                fw.write(coordinateofPFC[i][j] + "\r\n");
            }
        }

        fw.write("distance matrix\r\n");
        for (int i = 0; i < distanceMatrix.length; i++) {
            for (int j = 0; j < distanceMatrix[0].length; j++) {
                fw.write(distanceMatrix[i][j] + "\r\n");
            }
        }

        fw.write("ENDDATA\r\n");
        fw.flush();
        fw.close();
    }

    public Instance fileInput(int divide, int experimentnumber, String time) throws IOException {

        Instance instance = new Instance();

        String inputFilePath = "data/random_U/" + divide + ".txt";
        BufferedReader br = new BufferedReader(new FileReader(inputFilePath));

        br.readLine();
        String str = br.readLine();
        StringTokenizer st = new StringTokenizer(str);
        divide = (int) Double.parseDouble(st.nextToken());

        br.readLine();
        str = br.readLine();
        st = new StringTokenizer(str);
        numofCustomer = (int) Double.parseDouble(st.nextToken());

        br.readLine();
        str = br.readLine();
        st = new StringTokenizer(str);
        numofPFC = (int) Double.parseDouble(st.nextToken());

        br.readLine();
        str = br.readLine();
        st = new StringTokenizer(str);
        numofTask = (int) Double.parseDouble(st.nextToken());

        br.readLine();
        str = br.readLine();
        st = new StringTokenizer(str);
        c1 = Double.parseDouble(st.nextToken());

        br.readLine();
        str = br.readLine();
        st = new StringTokenizer(str);
        c2 = Double.parseDouble(st.nextToken());

        br.readLine();
        str = br.readLine();
        st = new StringTokenizer(str);
        miu = Double.parseDouble(st.nextToken());

        br.readLine();
        str = br.readLine();
        st = new StringTokenizer(str);
        a = Double.parseDouble(st.nextToken());

        br.readLine();
        str = br.readLine();
        st = new StringTokenizer(str);
        b = Double.parseDouble(st.nextToken());

        br.readLine();
        str = br.readLine();
        st = new StringTokenizer(str);
        Len = Double.parseDouble(st.nextToken());

        br.readLine();
        str = br.readLine();
        st = new StringTokenizer(str);
        Fi = Double.parseDouble(st.nextToken());

        br.readLine();
        str = br.readLine();
        st = new StringTokenizer(str);
        Fm = Double.parseDouble(st.nextToken());

        delta = new double[numofPFC];
        br.readLine();
        for (int i = 0; i < numofPFC; i++) {
            str = br.readLine();
            st = new StringTokenizer(str);
            delta[i] = Double.parseDouble(st.nextToken());
        }

        ODdemand = new int[numofCustomer][numofCustomer];

        br.readLine();
        for (int i = 0; i < numofCustomer; i++) {
            for (int j = 0; j < numofCustomer; j++) {
                str = br.readLine();
                st = new StringTokenizer(str);
                ODdemand[i][j] = (int) Double.parseDouble(st.nextToken());
            }
        }

        coordinateofCustomer = new double[numofCustomer][2];

        br.readLine();
        for (int i = 0; i < coordinateofCustomer.length; i++) {
            for (int j = 0; j < coordinateofCustomer[0].length; j++) {
                str = br.readLine();
                st = new StringTokenizer(str);
                coordinateofCustomer[i][j] = Double.parseDouble(st.nextToken());
            }
        }

        coordinateofPFC = new double[numofPFC][2];

        br.readLine();
        for (int i = 0; i < coordinateofPFC.length; i++) {
            for (int j = 0; j < coordinateofPFC[0].length; j++) {
                str = br.readLine();
                st = new StringTokenizer(str);
                coordinateofPFC[i][j] = Double.parseDouble(st.nextToken());
            }
        }

        distanceMatrix = new double[numofTask][numofTask];

        br.readLine();
        for (int i = 0; i < distanceMatrix.length; i++) {
            for (int j = 0; j < distanceMatrix[0].length; j++) {
                str = br.readLine();
                st = new StringTokenizer(str);
                distanceMatrix[i][j] = Double.parseDouble(st.nextToken());
            }
        }

        br.close();

        instance.divide = divide;
        instance.numofCustomer = numofCustomer;
        instance.numofPFC = numofPFC;
        instance.numofTask = numofTask;

        instance.a = a;
        instance.b = b; // platoon saving factor
        instance.Len = Len; // maximum platoon length

        instance.c1 = c1; // cost weight
        instance.c2 = c2;
        instance.miu = miu;
        instance.Fi = Fi;
        instance.Fm = Fm;
        instance.delta = delta;

        instance.ODdemand = ODdemand;
        instance.distanceMatrix = distanceMatrix;

        instance.coordinateofPFC = coordinateofPFC;
        instance.coordinateofCustomer = coordinateofCustomer;

        return instance;
    }

    public double distance(double x1, double y1, double x2, double y2) {
        double truckspeed = 1;
        double dis = Math.sqrt((Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2))) / truckspeed;
        return dis;
    }
}
